package main

import (
	mgo "gopkg.in/mgo.v2"
	"gopkg.in/mgo.v2/bson"
)

type DBOperation struct {
	session *mgo.Session
	dbName  string
}

const (
	CollectionReceivers              string = "receivers"
	CollectionPositions              string = "positions"
	CollectionPositionsLast          string = "positionslast"
	CollectionTireRawDatas           string = "tirerawdatas"
	CollectionTireRawDatasLast       string = "tirerawdataslast"
	CollectionCustomers              string = "customers"
	CollectionCompanies              string = "companies"
	CollectionTeams                  string = "teams"
	CollectionOrganizationProperties string = "organizationproperties"
)

const (
	UserTypeAdministrator int = 0
	UserTypeTeamLeader    int = 1
	UserTypeDriver        int = 2
	UserTypeIndividual    int = 3
	UserTypeSystemUser    int = 100
)

func NewDBOperation(cfg *Config) (*DBOperation, error) {
	session, err := mgo.Dial(cfg.DBUrl)
	if err != nil {
		return nil, err
	}
	session.SetPoolLimit(100)

	dbo := DBOperation{session, cfg.DBName}

	return &dbo, nil
}

func (p *DBOperation) Close() {
	p.session.Close()
}

func (p *DBOperation) companyReceivers(companyId int) []string {
	s := p.session.Copy()
	defer s.Close()

	var res []map[string]string
	rids := make([]string, 0)

	c := s.DB(p.dbName).C(CollectionReceivers)
	err := c.Find(bson.M{"cid": companyId}).Select(bson.M{"_id": 0, "rid": 1}).All(&res)
	if err == nil {
		for _, v := range res {
			if v["rid"] != "" {
				rids = append(rids, v["rid"])
			}
		}
	}

	return rids
}

func (p *DBOperation) teamReceivers(teamId []string) []string {
	s := p.session.Copy()
	defer s.Close()

	var res []map[string]string
	rids := make([]string, 0)

	c := s.DB(p.dbName).C(CollectionReceivers)
	err := c.Find(bson.M{"tids": bson.M{"$in": teamId}, "rid": bson.M{"$exists": 1}}).Select(bson.M{"_id": 0, "rid": 1}).All(&res)
	if err == nil {
		for _, v := range res {
			if v["rid"] != "" {
				rids = append(rids, v["rid"])
			}
		}
	}

	return rids
}

func (p *DBOperation) newPosition(rids []string, _id bson.ObjectId, maxCount int) []GPSDataT {
	s := p.session.Copy()
	defer s.Close()

	var res []GPSDataT
	var err error
	c := s.DB(p.dbName).C(CollectionPositionsLast)
	bsonSelect := bson.M{"_id:": 1, "rid": 1, "date": 1, "time": 1, "lat": 1, "lng": 1, "speed": 1, "dir": 1, "add": 1}
	if _id == "" {
		err = c.Find(bson.M{"rid": bson.M{"$in": rids}}).Select(bsonSelect).
			Sort("-_id").Limit(1).All(&res)
	} else {
		err = c.Find(bson.M{"_id": bson.M{"$gt": _id}, "rid": bson.M{"$in": rids}}).Select(bsonSelect).
			Sort("_id").Limit(maxCount).All(&res)
	}

	if err != nil {
		return nil
	} else {
		return res
	}
}

type TireDataRawT struct {
	Id        bson.ObjectId `bson:"_id"`
	Rid       string        `bson:"rid"`
	Date      int           `bson:"date"`
	Time      int           `bson:"time"`
	Latitude  float64       `bson:"lat"`
	Longitude float64       `bson:"lng"`
	Tires     []TireDataT   `bson:"tires"`
}

type TireDataT struct {
	CardId            int     `bson:"cardid"`
	SerialNum         int     `bson:"sn"`
	SensorId          string  `bson:"sid"`
	Pressure          float32 `bson:"pres"`
	Temperature       int     `bson:"temp"`
	Voltage           float32 `bson:"vol"`
	PressureStatus    int     `bson:"pstat"`
	TemperatureStatus int     `bson:"tstat"`
	PressureHighOrLow int     `bson:"phl"`
	Learned           int     `bson:"ms"`
	NoData            int     `bson:"nodata"`
	VoltageStatus     int     `bson:"vstat"`
}

func (p *DBOperation) newTire(rids []string, _id bson.ObjectId, maxCount int) []TireDataRawT {
	s := p.session.Copy()
	defer s.Close()

	var res []TireDataRawT
	var err error
	c := s.DB(p.dbName).C(CollectionTireRawDatasLast)
	bsonSelect := bson.M{"_id:": 1, "rid": 1, "date": 1, "time": 1, "lat": 1, "lng": 1, "tires": 1}
	if _id == "" {
		err = c.Find(bson.M{"rid": bson.M{"$in": rids}}).Select(bsonSelect).
			Sort("-_id").Limit(1).All(&res)
	} else {
		err = c.Find(bson.M{"_id": bson.M{"$gt": _id}, "rid": bson.M{"$in": rids}}).Select(bsonSelect).
			Sort("_id").Limit(maxCount).All(&res)
	}

	if err != nil {
		return nil
	} else {

		for i := 0; i < len(res); i++ {

			if res[i].Date > 0 && res[i].Time > 0 {
				tempTires := []TireDataT{}
				for _, tire := range res[i].Tires {
					if tire.Learned == 0 {
						tempTires = append(tempTires, tire)
					}
				}

				res[i].Tires = tempTires
			}
		}
		return res
	}
}

func (p *DBOperation) getRidType(rid string) int {
	s := p.session.Copy()
	defer s.Close()

	c := s.DB(p.dbName).C(CollectionReceivers)
	var res map[string]int

	err := c.Find(bson.M{"rid": rid}).Select(bson.M{"_id": 0, "type": 1}).One(&res)
	if err != nil {

		return -1
	}

	return res["type"]
}
